#include "exif.h"
#include <time.h>  

exif::exif()
{
	MotorolaOrder = 0;
}
void exif::Put16u(void * Short, unsigned short PutValue)
{
    if (MotorolaOrder){
        ((unsigned char *)Short)[0] = (unsigned char)(PutValue>>8);
        ((unsigned char *)Short)[1] = (unsigned char)PutValue;
    }else{
        ((unsigned char *)Short)[0] = (unsigned char)PutValue;
        ((unsigned char *)Short)[1] = (unsigned char)(PutValue>>8);
    }

}

int exif::Get16u(void * Short)
{
    if (MotorolaOrder){
        return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
    }else{
        return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0];
    }

}

int exif::Get32s(void * Long)
{
    if (MotorolaOrder){
        return  ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16)
              | (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 );
    }else{
        return  ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16)
              | (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 );
    }

}

void exif::Put32u(void * Value, unsigned PutValue)
{
    if (MotorolaOrder){
        ((unsigned char *)Value)[0] = (unsigned char)(PutValue>>24);
        ((unsigned char *)Value)[1] = (unsigned char)(PutValue>>16);
        ((unsigned char *)Value)[2] = (unsigned char)(PutValue>>8);
        ((unsigned char *)Value)[3] = (unsigned char)PutValue;
    }else{
        ((unsigned char *)Value)[0] = (unsigned char)PutValue;
        ((unsigned char *)Value)[1] = (unsigned char)(PutValue>>8);
        ((unsigned char *)Value)[2] = (unsigned char)(PutValue>>16);
        ((unsigned char *)Value)[3] = (unsigned char)(PutValue>>24);
    }

}

unsigned exif::Get32u(void * Long)
{
    return (unsigned)Get32s(Long) & 0xffffffff;

}

void exif::create_simple_EXIF(char *Buffer, int thumbnail_offset,int thumbnail_size)
{
    unsigned short NumEntries;
    int DataWriteIndex;
    int DateIndex;
    int DirIndex;
    int DirContinuation;
    time_t cur_time;
    char timeString[20];
    struct tm *ltime;
    time(&cur_time);
    ltime = localtime(&cur_time);
    sprintf(timeString, "%d:%02d:%02d %02d:%02d:%02d\n",
        1900 + ltime->tm_year,
	ltime->tm_mon + 1,
	ltime->tm_mday,
	ltime->tm_hour,
	ltime->tm_min,
	ltime->tm_sec
    );
    MotorolaOrder = 0;

    memcpy(Buffer, "Exif\0\0II",8);
    Put16u(Buffer+8, 0x2a);

    DataWriteIndex = 14;
    Put32u(Buffer+10, DataWriteIndex-6); // first IFD offset.  Means start 14 bytes in.
    {
        DirIndex = DataWriteIndex;
        NumEntries = 2;
        DataWriteIndex += 2 + NumEntries*12 + 4;

        Put16u(Buffer+DirIndex, NumEntries); // Number of entries
        DirIndex += 2;
  
        // Enitries go here...
        {
            // Date/time entry
            Put16u(Buffer+DirIndex, TAG_DATETIME);         // Tag
            Put16u(Buffer+DirIndex + 2, FMT_STRING);       // Format
            Put32u(Buffer+DirIndex + 4, 20);               // Components
            Put32u(Buffer+DirIndex + 8, DataWriteIndex-6); // Pointer or value.
            DirIndex += 12;

            DateIndex = DataWriteIndex;
            // If we had a pre-existing exif header, use time from that.
            memcpy(Buffer+DataWriteIndex, timeString, 19);
            Buffer[DataWriteIndex+19] = '\0';

            DataWriteIndex += 20;
        
            // Link to exif dir entry
            Put16u(Buffer+DirIndex, TAG_EXIF_OFFSET);      // Tag
            Put16u(Buffer+DirIndex + 2, FMT_ULONG);        // Format
            Put32u(Buffer+DirIndex + 4, 1);                // Components
            Put32u(Buffer+DirIndex + 8, DataWriteIndex-6); // Pointer or value.
            DirIndex += 12;
        }

        // End of directory - contains optional link to continued directory.
        DirContinuation = DirIndex;
    }

    {
        DirIndex = DataWriteIndex;
        NumEntries = 1;
        DataWriteIndex += 2 + NumEntries*12 + 4;

        Put16u(Buffer+DirIndex, NumEntries); // Number of entries
        DirIndex += 2;

        // Original date/time entry
        Put16u(Buffer+DirIndex, TAG_DATETIME_ORIGINAL);         // Tag
        Put16u(Buffer+DirIndex + 2, FMT_STRING);       // Format
        Put32u(Buffer+DirIndex + 4, 20);               // Components
        Put32u(Buffer+DirIndex + 8, DataWriteIndex-6); // Pointer or value.
        DirIndex += 12;

        memcpy(Buffer+DataWriteIndex, Buffer+DateIndex, 20);
        DataWriteIndex += 20;
        
        // End of directory - contains optional link to continued directory.
        Put32u(Buffer+DirIndex, 0);
    }

    {
        //Continuation which links to this directory;
        Put32u(Buffer+DirContinuation, DataWriteIndex-6);
        DirIndex = DataWriteIndex;
        NumEntries = 2;
        DataWriteIndex += 2 + NumEntries*12 + 4;

        Put16u(Buffer+DirIndex, NumEntries); // Number of entries
        DirIndex += 2;
        {
            // Link to exif dir entry
            Put16u(Buffer+DirIndex, TAG_THUMBNAIL_OFFSET);         // Tag
            Put16u(Buffer+DirIndex + 2, FMT_ULONG);       // Format
            Put32u(Buffer+DirIndex + 4, 1);               // Components
            Put32u(Buffer+DirIndex + 8, thumbnail_offset); // Pointer or value.
           // printf("TAG_THUMBNAIL_OFFSET 0x%X\n", thumbnail_offset);
            DirIndex += 12;

        }

        {
            // Link to exif dir entry
            Put16u(Buffer+DirIndex, TAG_THUMBNAIL_LENGTH);         // Tag
            Put16u(Buffer+DirIndex + 2, FMT_ULONG);       // Format
            Put32u(Buffer+DirIndex + 4, 1);               // Components
            Put32u(Buffer+DirIndex + 8,  thumbnail_size); // Pointer or value.
            //printf("TAG_THUMBNAIL_LENGTH 0x%X\n", thumbnail_size);
            DirIndex += 12;
        }

        // End of directory - contains optional link to continued directory.
        Put32u(Buffer+DirIndex, 0);
    }

}


